#pragma once
#include "requestor.hpp"

namespace Client
{
    class Provider
    {
    public:
        using ptr = shared_ptr<Provider>;
        Provider(const Requestor::ptr requestor) : _requestor(requestor) {}
        bool RegistryMethod(const BaseConnection::ptr &conn, const string &method, const Address &host)
        {
            auto msg_req = MessageFactory::create<ServiceRequest>();
            msg_req->SetId(UUID::uuid());
            msg_req->SetHost(host);
            msg_req->SetMethod(method);
            msg_req->SetMtype(Mtype::REQ_SERVICE);
            msg_req->SetServiceOp(ServiceOptype::SERVICE_REGISTRY);

            BaseMessage::ptr msg_rsp;
            bool ret = _requestor->Send(conn, msg_req, msg_rsp);
            if (ret == false)
            {
                ELog("%s服务注册失败", method.c_str());
            }
            auto service_rsp = std::dynamic_pointer_cast<ServiceResponse>(msg_rsp);
            if (msg_rsp.get() == nullptr)
            {
                ELog("向下转化失败");
                return false;
            }
            if (service_rsp->GetRcode() != RCode::RCODE_OK)
            {
                ELog("服务注册失败，原因%s", ErrReason(service_rsp->GetRcode()).c_str());
                return false;
            }
            return true;
        }

    private:
        Requestor::ptr _requestor;
    };

    class MethodHost
    {
    public:
        using ptr = shared_ptr<MethodHost>;
        MethodHost() : _idx(0) {}
        MethodHost(const vector<Address> &hosts) : _hosts(hosts), _idx(0) {}
        void AppendHost(const Address &host)
        {
            unique_lock<mutex> lock(_mutex);
            _hosts.push_back(host);
        }
        void RemoveHost(const Address &host)
        {
            unique_lock<mutex> lock(_mutex);
            for (auto it = _hosts.begin(); it != _hosts.end(); it++)
            {
                if (*it == host)
                {
                    _hosts.erase(it);
                    break;
                }
            }
        }
        Address ChoseHost()
        {
            unique_lock<mutex> lock(_mutex);
            auto pos = _idx++ % _hosts.size();
            return _hosts[pos];
        }
        bool Empty()
        {
            return _hosts.empty();
        }

    private:
        mutex _mutex;
        size_t _idx;
        vector<Address> _hosts;
    };

    class Discoverer
    {
    public:
        using offline_cb=function<void(const Address&host)>;
        using ptr = shared_ptr<Discoverer>;
        Discoverer(const Requestor::ptr &requestor,const offline_cb &cb) : 
        _off_callback(cb),_requestor(requestor) {}
        bool ServiceDiscovery(const BaseConnection::ptr &conn, const string &method, Address &host)
        {
            {
                // 当前所保管提供信息者存在，则直接返回地址
                unique_lock<mutex> lock(_mutex);
                auto it = _method_hosts.find(method);
                if (it != _method_hosts.end())
                {
                    if (it->second->Empty() == false)
                    {
                        host = it->second->ChoseHost();
                        return true;
                    }
                }
            }
            // 当前提供者为空
            auto msg_req = MessageFactory::create<ServiceRequest>();
            msg_req->SetMethod(method);
            msg_req->SetId(UUID::uuid());
            msg_req->SetMtype(Mtype::REQ_SERVICE);
            msg_req->SetServiceOp(ServiceOptype::SERVICE_DISCOVERY);

            BaseMessage::ptr msg_rsp;
            bool ret = _requestor->Send(conn, msg_req, msg_rsp);

            if (ret == false)
            {
                ELog("服务发现失败");
                return false;
            }
            auto service_rsp = dynamic_pointer_cast<ServiceResponse>(msg_rsp);
            if (!service_rsp)
            {
                ELog("服务发现失败，向下转换失败!");
                return false;
            }
            if (service_rsp->GetRcode() != RCode::RCODE_OK)
            {
                ELog("服务发现失败!%s", ErrReason(service_rsp->GetRcode()).c_str());
                return false;
            }

            // 此时是没有主机能够对应的
            unique_lock<mutex> lock(_mutex);
            auto method_host = make_shared<MethodHost>(service_rsp->GetHosts());
            if (method_host->Empty())
            {
                ELog("%s 服务发现失败！没有能够提供服务的主机！", method.c_str());
                return false;
            }

            host = method_host->ChoseHost();
            _method_hosts[method] = method_host;
            return true;
        }

        // 这个接口来提供给Dispatch模块进行服务上线和下线请求处理的回调函数
        void OnServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
        {
            // 1.判断是上线还是下线、
            auto optype = msg->GetServiceOp();
            string method = msg->GetMethod();
            unique_lock<mutex> lock(_mutex);
            // 2.上线请求：找到Method_host新增一个主机地址
            if (optype == ServiceOptype::SERVICE_ONLINE)
            {
                auto it = _method_hosts.find(method);
                if (it == _method_hosts.end())
                {
                    // 没有找到就新建
                    auto method_host = make_shared<MethodHost>();
                    method_host->AppendHost(msg->Host());
                    _method_hosts[method] = method_host;
                }
                else
                {
                    it->second->AppendHost(msg->Host());
                }
            }
            else if (optype == ServiceOptype::SERVICE_OFFLINE)
            {
                // 3.下线请求：找到Method_host删除一个主机地址
                auto it = _method_hosts.find(method);
                if (it == _method_hosts.end())
                {
                    return ;
                }
                it->second->RemoveHost(msg->Host());
                _off_callback(msg->Host());
            }
        }

    private:
        mutex _mutex;
        offline_cb _off_callback;
        unordered_map<string, MethodHost::ptr> _method_hosts;
        Requestor::ptr _requestor;
    };
}